package com.eclipse.youdaotranslation.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.ConnectionPool;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class OkHttpUtil {
	private final int DEFAULT_TIMEOUT = 5000;
	private static OkHttpClient client;
	public static final MediaType FORM_CONTENT_TYPE_UTF8 = MediaType
			.parse("application/x-www-form-urlencoded; charset=utf-8");
	public static final MediaType FORM_CONTENT_TYPE_GBK = MediaType
			.parse("application/x-www-form-urlencoded; charset=gbk");
	public static final MediaType JSON_CONTENT_TYPE_UTF8 = MediaType.parse("application/json; charset=utf-8");
	private final HashMap<String, List<Cookie>> cookieStore = new HashMap<String, List<Cookie>>();

	private static class OkHttpHolder {
		private static OkHttpUtil instance = new OkHttpUtil();
	}

	public OkHttpUtil() {
		ConnectionPool connectionPool = new ConnectionPool(100, 30, TimeUnit.MINUTES);
		client = new OkHttpClient.Builder().connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
				.readTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
				.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS).retryOnConnectionFailure(true)
				.connectionPool(connectionPool).cookieJar(new CookieJar() {
					@Override
					public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
						System.out.println("cookies: " + list.size());
						List<Cookie> cookies = cookieStore.get(httpUrl.host());
						if (cookies == null)
							cookies = new ArrayList<Cookie>();
						LinkedHashSet<Cookie> set = new LinkedHashSet<Cookie>();
						set.addAll(cookies);
						if (list != null) {
							set.addAll(list);
						}
						cookies.clear();
						cookies.addAll(set);
						cookieStore.put(httpUrl.host(), cookies);
						if (cookies != null) {
							for (int i = 0; i < cookies.size(); i++)
								System.out.println(cookies.size() + "cookies: " + cookies.get(i));
						}
					}

					@Override
					public List<Cookie> loadForRequest(HttpUrl httpUrl) {
						System.out.println(httpUrl.toString());
						List<Cookie> cookies = cookieStore.get(httpUrl.host());
						if (cookies != null) {
							for (int i = 0; i < cookies.size(); i++)
								System.out.println(cookies.size() + "cookies: " + cookies.get(i));
						}
						return cookies != null ? cookies : new ArrayList<Cookie>();
					}
				}).build();
	}

	public static void addCookie(String hosts, Map<String, String> namevalue) {
		HttpUrl host = HttpUrl.parse(hosts);
		List<Cookie> list = getInstance().cookieStore.get(host.host());
		if (list == null || list.size() < 1)
			list = new ArrayList<Cookie>();
		if (namevalue != null && !namevalue.isEmpty()) {
			for (String key : namevalue.keySet()) {
				Cookie Cookie = new Cookie.Builder().domain(host.host()).name(key).value(namevalue.get(key)).build();
				for (int i = 0; i < list.size(); i++) {
					Cookie item = list.get(i);
					if (item.name().equals(Cookie.name())) {
						list.remove(i);
					}
				}
				list.add(Cookie);
			}
		}
		getInstance().cookieStore.put(host.host(), list);
	}

	public static void addCookie(String hosts, List<String> listCookie) {
		HttpUrl host = HttpUrl.parse(hosts);
		List<Cookie> list = getInstance().cookieStore.get(host.host());
		if (list == null || list.size() < 1)
			list = new ArrayList<Cookie>();
		for (String cookie : listCookie) {
			if (cookie.contains("OUTFOX_SEARCH_USER_ID")) {
				String tmphosts = "http://fanyi.youdao.com";
				host = HttpUrl.parse(tmphosts);
			}
			Cookie e = Cookie.parse(host, cookie);
			host = HttpUrl.parse(hosts);
			list.add(e);
		}
		getInstance().cookieStore.put(host.host(), list);
	}

	public static int getCookieSize(String hosts) {
		HttpUrl httpUrl = HttpUrl.parse(hosts);
		return OkHttpHolder.instance.cookieStore.get(httpUrl.host()).size();
	}
	
	public static List<Cookie> getCookie(HttpUrl httpUrl) {
		return OkHttpHolder.instance.cookieStore.get(httpUrl.host());
	}

	public static OkHttpUtil getInstance() {
		return OkHttpHolder.instance;
	}

	public OkHttpClient getClient() {
		return client;
	}

	public String doGetWithJsonResult(String uri) throws IOException {
		Request request = new Request.Builder().url(uri).build();

		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);

		String json = null;
		json = response.body().string();

		return json;
	}

	public InputStream doGetWithStream(String uri, Headers headers) throws IOException {
		Request request = null;
		if (headers == null) {
			request = new Request.Builder().url(uri).build();
		} else {
			request = new Request.Builder().url(uri).headers(headers).build();
		}

		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);

		return response.body().byteStream();
	}

	public Response doGetWithResponse(String uri) throws IOException {
		Request request = new Request.Builder().url(uri).build();

		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);
		return response;
	}

	public String doPostWithJsonResult(String uri, Map<String, String> paramMap, Headers headers) throws Exception {
		RequestBody formBody = null;
		Charset UTF_8 = Charset.forName("UTF-8");
		FormBody.Builder formEncodingBuilder = new FormBody.Builder(UTF_8);
		if (paramMap != null && !paramMap.isEmpty()) {
			for (String key : paramMap.keySet()) {
				formEncodingBuilder.add(key, paramMap.get(key));
			}
		}
		formBody = formEncodingBuilder.build();

		Request request = null;
		if (headers == null) {
			request = new Request.Builder().url(uri).post(formBody).build();
		} else {
			request = new Request.Builder().url(uri).post(formBody).headers(headers).build();
		}

		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);

		String json = "";

		json = response.body().string();

		return json;
	}

	public String doPostWithJsonResult(String uri, Map<String, String> paramMap) throws IOException {
		RequestBody formBody = null;
		Charset UTF_8 = Charset.forName("UTF-8");
		FormBody.Builder formEncodingBuilder = new FormBody.Builder(UTF_8);
		if (paramMap != null && !paramMap.isEmpty()) {
			for (String key : paramMap.keySet()) {
				formEncodingBuilder.add(key, paramMap.get(key));
			}
		}
		formBody = formEncodingBuilder.build();

		Request request = new Request.Builder().url(uri).post(formBody).build();
		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);

		String json = null;
		json = response.body().string();

		return json;
	}

	public static byte[] chunked(InputStream in) throws Exception {
		ByteArrayOutputStream tmpos = new ByteArrayOutputStream(4);
		ByteArrayOutputStream bytes = new ByteArrayOutputStream();
		int data = -1;
		int[] aaa = new int[2];
		byte[] aa = null;

		while ((data = in.read()) >= 0) {
			aaa[0] = aaa[1];
			aaa[1] = data;
			if (aaa[0] == 13 && aaa[1] == 10) {
				aa = tmpos.toByteArray();
				int num = 0;
				try {
					num = Integer.parseInt(new String(aa, 0, aa.length - 1).trim(), 16);
				} catch (Exception e) {
					System.out.println("aa.length:" + aa.length);
					e.printStackTrace();
				}

				if (num == 0) {

					in.read();
					in.read();
					return bytes.toByteArray();
				}
				aa = new byte[num];
				int sj = 0, ydlen = num, ksind = 0;
				while ((sj = (in.read(aa, ksind, ydlen))) < ydlen) {
					ydlen -= sj;
					ksind += sj;
				}

				bytes.write(aa);
				in.read();
				in.read();
				tmpos.reset();
			} else {
				tmpos.write(data);
			}
		}
		return tmpos.toByteArray();
	}

	public String doPostWithJsonResultGbk(String uri, Map<String, String> paramMap) throws IOException {
		RequestBody formBody = null;
		Charset gbk = Charset.forName("GBK");
		FormBody.Builder formEncodingBuilder = new FormBody.Builder(gbk);
		if (paramMap != null && !paramMap.isEmpty()) {
			for (String key : paramMap.keySet()) {
				formEncodingBuilder.add(key, paramMap.get(key));
			}
		}
		formBody = formEncodingBuilder.build();

		Request request = new Request.Builder().url(uri).post(formBody).build();
		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);

		String json = null;
		json = response.body().string();

		return json;
	}

	public String doPostJsonSync(String uri, String jsonObj) throws IOException {
		RequestBody requestBody = RequestBody.create(JSON_CONTENT_TYPE_UTF8, jsonObj);
		Request request = new Request.Builder().url(uri).post(requestBody).build();
		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);

		String json = null;
		json = response.body().string();

		return json;
	}

	public String doPostJsonAsyn(String uri, String jsonObj) throws IOException {
		RequestBody requestBody = RequestBody.create(JSON_CONTENT_TYPE_UTF8, jsonObj);
		Request request = new Request.Builder().url(uri).post(requestBody).build();
		Call call = client.newCall(request);
		call.enqueue(new Callback() {
			@Override
			public void onFailure(Call call, IOException e) {
				System.out.println(e.getMessage());
			}

			@Override
			public void onResponse(Call call, Response response) throws IOException {
				if (response.isSuccessful()) {
					System.out.println(response.body().string());
				}
			}
		});
		String json = "success";

		return json;
	}

	public String doPostWithBodyAndHeader(String uri, RequestBody formBody, Headers headers) throws IOException {
		Request request = new Request.Builder().headers(headers).url(uri).post(formBody).build();

		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);

		String json = null;
		json = response.body().string();

		return json;
	}

	public String doPostWithBodyAndHeader(String uri, RequestBody formBody) throws IOException {
		Request request = new Request.Builder().url(uri).post(formBody).build();

		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);

		String json = null;
		json = response.body().string();

		return json;
	}

	public Map<String, List<String>> doHeadWithHeader(String uri, Headers headers) throws IOException {
		Request request = new Request.Builder().url(uri).head().build();// .headers(headers)

		Response response = client.newCall(request).execute();
		if (!response.isSuccessful())
			throw new IOException("Unexpected code " + response);
		Map<String, List<String>> maps = response.headers().toMultimap();
		response.close();
		return maps;
	}
}
